package mi.payment.utils.transaction;

import android.content.Context;
import android.text.TextUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import mi.payment.R;
import mi.payment.bean.db.TradeData;
import mi.payment.constants.CARDTYPE;
import mi.payment.constants.TransactionBitmap;
import mi.payment.db.dao.PayDetail;
import mi.payment.settings.SystemParamsOperation;
import mi.payment.settings.SystemParamsSettings;
import mi.payment.utils.datacollection.PayDetailCollection;
import mi.payment.utils.iso8583.DecodePackage;
import mi.payment.utils.iso8583.EncodePackage;
import mi.payment.utils.iso8583.FieldUtils;
import mi.payment.utils.iso8583.MsgField;
import mi.payment.utils.iso8583.Utils;
import mi.payment.utils.secure.TerminalSecure;
import sunmi.sunmiui.utils.LogUtil;

/**
 * 冲正交易
 *
 * @author longt on 2017/2/5.
 */
public class CorrectTask extends TransactionTask<PayDetail, Integer, String> {

    private static final String TAG = "CorrectTask";

    public CorrectTask(Context ctx) {
        super(ctx, false);
    }

    @Override
    protected void onBegin(PayDetail[] params) {
    }

    @Override
    protected String appointResult() {
        return null;
    }

    @Override
    protected Map<String, MsgField> preAssembly() {
        return null;
    }

    @Override
    protected byte[] changeAndAssembly(Map<String, MsgField> fieldMap) {
        return new byte[0];
    }

    @Override
    protected String doTransactionSelf() {
        String ret = "96";
        PayDetail pay = mPayDetailModel.getLastWaitForCorrection();
        if (pay == null) {
            LogUtil.e(TAG, "找不到需要冲正的数据...");
            return ret;
        }
        LogUtil.e(TAG, "正在冲正...");

        sendBroadcastForDialog(R.string.correcting);
        SystemParamsOperation systemParamsOperation = SystemParamsOperation.getInstance();
        SystemParamsSettings systemParamsSettings = systemParamsOperation.getSystemParamsSettings();
        int correctFrequency = systemParamsSettings.getCorrectFrequency();
        // 重试次数
        int count = correctFrequency - 1;
        for (int i = 0; i <= count; i++) {
            boolean needContinueCorrect = isNeedContinueCorrect(ret);
            if (needContinueCorrect) {
                LogUtil.e(TAG, "冲正开始:第" + i + "次");
                ret = correct(pay);
                LogUtil.e(TAG, "冲正結果:第" + i + "次 ret = " + ret);
            } else {
                LogUtil.e(TAG, "冲正成功..." + ret);
                sendBroadcastForDialog(R.string.base_pwd_connecting);
                pay.isNeedReversal = false;
                pay.isReversal = true;
                pay.correctAnswerCode = ret;
                mPayDetailModel.update(pay);
                return ret;
            }
        }
        sendBroadcastForDialog(R.string.base_pwd_connecting);
        LogUtil.e(TAG, "冲正结束..." + ret);
        return ret;
    }

    private String correct(PayDetail pay) {
        String tradeAnswerCode = pay.tradeAnswerCode;
        LogUtil.e(TAG, "begin correct:" + pay.voucherNo + " tradeAnswerCode = " + tradeAnswerCode);
        TradeData tradeData = mPayDetailModel.getTradeDataByVoucherNo(pay.voucherNo);
        pay = tradeData.getPayDetail();
        Map<String, MsgField> transPackage = EncodePackage.preAssemblyBase(TransactionBitmap.BITMAP_CONSUMPTION_CORRECT);
        // 由下列情形引发冲正
        // POS终端在时限内未能收到POS中心的应答消息而引发，冲正原因码填“98”。
        // POS终端在时限内收到POS中心的批准应答消息，但由于POS机故障无法完成交易而引发，冲正原因码填“96”。
        // POS终端对收到POS中心的应答消息，验证MAC出错，冲正原因码填“A0”。
        // 其他情况，冲正原因码填“06”。
        // 39域是68 填98，39域是B6填A0，暂时将96的情况归到06里
        pay.setReversalReason("06");
        boolean judge = pay.getTradeAnswerCode().equals("68") && TextUtils.isEmpty(pay.reversalReason);
        if (judge) {
            pay.setReversalReason("98");
        }
        judge = pay.getTradeAnswerCode().equals("B6") && TextUtils.isEmpty(pay.reversalReason);
        if (judge) {
            pay.setReversalReason("A0");
        }

        // 更新预组装的Map
        transPackage = FieldUtils.fillEachFieldValue(transPackage, tradeData);

        MsgField f055 = transPackage.get("F055");
        if (f055 != null) {
            String str55 = "";
            String ic55 = f055.getDataStr();
            if (ic55 != null && ic55.length() > 0) {
                int indexOf = ic55.indexOf("9505");
                if (indexOf != -1) {
                    str55 = ic55.substring(indexOf, indexOf + 14);
                }
                indexOf = ic55.indexOf("9F1E08");
                if (indexOf != -1) {
                    str55 += ic55.substring(indexOf, indexOf + 22);
                }
                indexOf = ic55.indexOf("9F10");
                if (indexOf != -1) {
                    String len = ic55.substring(indexOf + 4, indexOf + 6);
                    int parseInt = Integer.parseInt(len, 16);
                    str55 += ic55.substring(indexOf, indexOf + 6 + parseInt * 2);
                }
                indexOf = ic55.indexOf("9F3602");
                if (indexOf != -1) {
                    str55 += ic55.substring(indexOf, indexOf + 10);
                }
                indexOf = ic55.indexOf("DF31");
                if (indexOf != -1) {
                    String len = ic55.substring(indexOf + 4, indexOf + 6);
                    int parseInt = Integer.parseInt(len, 16);
                    str55 += ic55.substring(indexOf, indexOf + 6 + parseInt * 2);
                }
                if (str55 != null && str55.length() > 0) {
                    f055.setDataStr(str55);
                }
            }
        }

        // 填写60域
        MsgField f060 = transPackage.get("F060");
        String value60 = pay.getTransType() + pay.getBathNo() + pay.getNetManageCode();
        String value60_4 = "6";
        if (CARDTYPE.IC.getValue() == pay.cardType) {
            value60_4 = "5";
        }
        value60 += value60_4;
        value60 += "0";
        f060.setDataStr(value60);

        // 填写61域
        MsgField f061 = transPackage.get("F061");
        String value61 = pay.originalBathNo + pay.originalPOSNum + pay.originalTransDate;
        f061.setDataStr(value61);

        // 组包，得到组包后的报文
        byte[] sendBytes = EncodePackage.assembly(transPackage, "0400", TerminalSecure.PROCESSREQUEST_NONE);

        // 报文上送
        String byte2HexStr = Utils.byte2HexStr(sendBytes);
        LogUtil.e(TAG, "冲正报文上送: " + byte2HexStr);

        String ret;
        int[] rLen = new int[1];
        byte[] recBuff = new byte[2048];
        try {
            POSPAccess pospAccess = new POSPAccess();
            pospAccess.Transaction(sendBytes, sendBytes.length, recBuff, rLen);
            int temp = rLen[0];
            recBuff = Arrays.copyOf(recBuff, temp);
            pay.setReceiverBag(recBuff);
        } catch (Exception e) {
            e.printStackTrace();
            ret = e.getMessage();
            LogUtil.e(TAG, "冲正超时");
            return ret;
        }

        // 打印返回报文
        int temp = rLen[0];
        ret = String.valueOf(temp) + ":";
        for (int i = 0; i < temp; i++) {
            byte b = recBuff[i];
            ret += String.format("%02X", b);
        }
        LogUtil.e(TAG, "冲正报文返回:" + ret);

        // 解包
        HashMap<String, MsgField> resp = DecodePackage.unAssembly(recBuff);

        // 返回报文校验
        String checkRet = checkTransactionMsg(sendBytes, transPackage, recBuff, resp);

        // MAC验证失败
        boolean b = "B6".equals(checkRet) || "96".equals(checkRet);
        if (b) {
            LogUtil.e(TAG, "冲正报文校验失败" + checkRet);
            return checkRet;
        }

        // 将返回报文回填到bean并更新数据库
        FieldUtils.fillBeanByMap(tradeData, resp);
        MsgField f039 = resp.get("F039");
        if (f039 != null) {
            ret = f039.getDataStr();
            pay.isReversal = true;
            pay.isNeedReversal = false;
            pay.correctAnswerCode = ret;
            pay.tradeAnswerCode = tradeAnswerCode;
        }
        mPayDetailModel.update(pay);

        PayDetailCollection.getInstance().setCorrectTransaction(true);
        PayDetailCollection.getInstance().uploadData(pay);
        return ret;
    }

    /**
     * 是否冲正成功
     */
    public static boolean isCorrectSuccess(String ret) {
        return TextUtils.equals("00", ret) || TextUtils.equals("12", ret) || TextUtils.equals("25", ret);
    }

    /**
     * 是否需要继续冲正
     */
    private boolean isNeedContinueCorrect(String ret) {
        return TextUtils.equals("E4", ret) || TextUtils.equals("68", ret) ||
                TextUtils.equals("98", ret) || TextUtils.equals("96", ret) ||
                TextUtils.equals("NE", ret);
    }


}
